package com.berwin.apkdistribution.view;

import com.alibaba.fastjson.JSONArray;
import com.berwin.apkdistribution.utils.UserDefault;
import com.meituan.android.walle.ChannelReader;
import com.meituan.android.walle.ChannelWriter;

import javax.swing.*;
import javax.swing.filechooser.FileFilter;
import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetAdapter;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.event.*;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.nio.file.Files;
import java.util.*;
import java.util.List;

public class MainView extends JFrame implements ActionListener {

    public static final String SEPARATOR = " <-> ";
    public static final String FILE_TYPE = ".apk";
    public static final String SUFFIX_EXPORT = "_out";
    public static final String KEY_CHANNEL = "channel";
    public static final String KEY_RECENT = "KEY_RECENT";
    public static final int MAX_RECENT = 5;

    private JLabel lblChannel = null;
    private JTextField tfImport = null;
    private JTextField tfExport = null;
    private JList<String> listAttribute = null;
    private Logger logger = null;

    private String apkImport = "";
    private String apkExport = "";
    private Map<String, String> mapApkInfo = new HashMap<String, String>();
    private java.util.List<String> recents = new ArrayList();
    private JMenu recentMenuItem;

    public MainView() {
        try {
            /**
             * 设置图形界面外观 java的图形界面外观有3种,默认是java的金属外观,还有就是windows系统,motif系统外观.
             * 1、Metal风格 (默认) UIManager.setLookAndFeel(
             * "javax.swing.plaf.metal.MetalLookAndFeel"); 2、Windows风格
             * UIManager.setLookAndFeel(
             * "com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); 3、Windows
             * Classic风格 UIManager.setLookAndFeel(
             * "com.sun.java.swing.plaf.windows.WindowsClassicLookAndFeel");
             * 4、Motif风格 UIManager.setLookAndFeel(
             * "com.sun.java.swing.plaf.motif.MotifLookAndFeel"); 5、Mac风格
             * (需要在相关的操作系统上方可实现) String lookAndFeel =
             * "com.sun.java.swing.plaf.mac.MacLookAndFeel"
             * ;UIManager.setLookAndFeel(lookAndFeel); 6、GTK风格 (需要在相关的操作系统上方可实现)
             * String lookAndFeel =
             * "com.sun.java.swing.plaf.gtk.GTKLookAndFeel";
             * UIManager.setLookAndFeel(lookAndFeel); 7、可跨平台的默认风格 String
             * lookAndFeel = UIManager.getCrossPlatformLookAndFeelClassName();
             * UIManager.setLookAndFeel(lookAndFeel); 8、当前系统的风格 String
             * lookAndFeel = UIManager.getSystemLookAndFeelClassName();
             * UIManager.setLookAndFeel(lookAndFeel);
             */
            if ("Mac OS X".equals(System.getProperties().getProperty("os.name"))) {
                UIManager
                        .setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
//                System.setProperty("apple.laf.useScreenMenuBar", "true");//设置程序的menubar显示到Mac的菜单栏上
                System.setProperty("com.apple.mrj.application.apple.menu.about.name", "BMFont工具");//设定Mac中程序运行时菜单栏显示
            } else {
                UIManager
                        .setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        this.setTitle("安卓渠道信息");
        Dimension screen = getToolkit().getScreenSize();
        float ratio = 0.5f;
        this.setSize(new Dimension((int) (screen.getWidth() * ratio), (int) (screen.getHeight() * ratio)));
        this.setLocationRelativeTo(null);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        this.initDrop();
        this.initMenuBar();
        this.add(this.initNorth(), BorderLayout.NORTH);
        this.add(this.initSouth(), BorderLayout.SOUTH);
        this.add(this.initCenter(), BorderLayout.CENTER);
        this.add(this.initWest(), BorderLayout.WEST);

        this.initData();
    }

    private void initData() {
        Object[] recents = UserDefault.getInstance().getValueForKey(KEY_RECENT, new Object[0]);
        this.recents = new ArrayList(Arrays.asList(recents));

        if (this.recents.size() > 0) {
            if (this.loadApk(this.recents.get(0))) {
                this.logger.logInfo("启动成功，已加载:" + this.tfImport.getText());
            }
        } else {
            this.logger.logWarn("启动成功，未加载apk");
        }
    }

    private void initMenuBar() {
        JMenuBar menuBar = new JMenuBar();
        this.setJMenuBar(menuBar);

        JMenu fileMenu = new JMenu("文件");
        menuBar.add(fileMenu);

        JMenuItem openMenuItem = new JMenuItem("打开");
        openMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.META_MASK));
        openMenuItem.addActionListener(this);
        fileMenu.add(openMenuItem);

        recentMenuItem = new JMenu("打开最近的文件");
//        recentMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R, ActionEvent.META_MASK));
        recentMenuItem.addActionListener(this);
        fileMenu.add(recentMenuItem);
        fileMenu.addSeparator();

        JMenuItem exitMenuItem = new JMenuItem("退出");
        exitMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, ActionEvent.META_MASK));
        exitMenuItem.addActionListener(this);
        fileMenu.add(exitMenuItem);

        // 关于
        JMenu menuAbout = new JMenu("关于");
        menuBar.add(menuAbout);

        JMenuItem linkAbout = new JMenuItem("开源地址");
        linkAbout.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_L, ActionEvent.META_MASK));
        linkAbout.addActionListener(this);
        menuAbout.add(linkAbout);
        menuAbout.addSeparator();

        JMenuItem itemAbout = new JMenuItem("关于");
        itemAbout.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, ActionEvent.META_MASK));
        itemAbout.addActionListener(this);
        menuAbout.add(itemAbout);
    }

    private JPanel initNorth() {
        JPanel north = new JPanel(new GridLayout(1, 1));
        north.setBorder(BorderFactory.createTitledBorder("导入/出路径"));

        JPanel row1 = new JPanel(new BorderLayout());

        JButton btnImportOpen = new JButton("打开");
        row1.add(btnImportOpen, BorderLayout.WEST);
        btnImportOpen.addActionListener(e -> {
            try {
                if ("".equals(this.apkImport)) {
                    this.logger.logWarn("APK文件未指定");
                    return;
                }
                File file = new File(this.apkImport);
                if (file.isDirectory())
                    Desktop.getDesktop().open(file);
                else
                    Desktop.getDesktop().open(file.getParentFile());
            } catch (Exception ex) {
                ex.printStackTrace();
                this.logger.logError("打开文件失败:" + ex.toString());
            }
        });

        tfImport = new JTextField();
        tfImport.setEditable(false);
        row1.add(tfImport, BorderLayout.CENTER);

        JButton btnImportBrowser = new JButton("浏览");
        row1.add(btnImportBrowser, BorderLayout.EAST);
        north.add(row1);
        btnImportBrowser.addActionListener(e -> {
            this._selectAPKFile();
        });

        return north;
    }

    private void _selectAPKFile() {
        // 选择apk文件
        String defFilePath = this.recents.size() > 0 ? this.recents.get(0) : this.tfImport.getText();
        JFileChooser fileChooser = new JFileChooser(defFilePath);
        fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
        fileChooser.setFileFilter(new FileFilter() {
            @Override
            public boolean accept(File f) {
                return f.getAbsolutePath().endsWith(MainView.FILE_TYPE);
            }

            @Override
            public String getDescription() {
                return "apk格式文件";
            }
        });
        fileChooser.setSelectedFile(new File(defFilePath));
        int i = fileChooser.showSaveDialog(this);
        if (i == JFileChooser.APPROVE_OPTION) {
            File selFile = fileChooser.getSelectedFile();
            String apkPath = selFile.getAbsolutePath();
            if (!apkPath.endsWith(MainView.FILE_TYPE)) {
                this.logger.logWarn("只支持APK文件格式");
                return;
            }
            // 处理
            this.loadApk(apkPath);
        }
    }

    private JPanel initWest() {
        JPanel west = new JPanel(new BorderLayout());
        west.setBorder(BorderFactory.createTitledBorder("渠道"));

        lblChannel = new JLabel("0");
        lblChannel.setFont(new Font(null, Font.BOLD, 50));
        west.add(lblChannel, BorderLayout.CENTER);

        JPanel bottom = new JPanel(new FlowLayout(FlowLayout.RIGHT));
        west.add(bottom, BorderLayout.SOUTH);
        JLabel lblEdit = new JLabel(new ImageIcon("./res/icon_edit.png"));
        bottom.add(lblEdit);
        lblEdit.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                super.mouseClicked(e);
                if ("".equals(MainView.this.apkImport)) {
                    MainView.this.logger.logWarn("APK文件未指定");
                    return;
                }
                String channel = MainView.this.mapApkInfo.get(MainView.KEY_CHANNEL);

                AttributeDialog attributeDialog = new AttributeDialog(MainView.this, "修改渠道", MainView.KEY_CHANNEL, channel, new AttributeDialog.OnAttributeSaveClicked() {
                    @Override
                    void onClicked(String key, String value) {
                        super.onClicked(key, value);
                        MainView.this.mapApkInfo.put(MainView.KEY_CHANNEL, value);
                        MainView.this._updateUI();
                    }
                });
                attributeDialog.setKeyEditable(false);
                attributeDialog.setVisible(true);
            }
        });


        return west;
    }

    private JPanel initCenter() {
        JPanel center = new JPanel(new BorderLayout());
        center.setBorder(BorderFactory.createTitledBorder("属性值"));

        center.add(this.initAttributes(), BorderLayout.CENTER);

        JButton btnAdd = new JButton("添加属性");
        center.add(btnAdd, BorderLayout.SOUTH);
        btnAdd.addActionListener(e -> {
            if ("".equals(this.apkImport)) {
                this.logger.logWarn("APK文件未指定");
                return;
            }

            AttributeDialog attributeDialog = new AttributeDialog(MainView.this, "添加属性", "", "", new AttributeDialog.OnAttributeSaveClicked() {
                @Override
                void onClicked(String key, String value) {
                    super.onClicked(key, value);
                    if (MainView.this.mapApkInfo.containsKey(key)) {
                        MainView.this.logger.logWarn("【" + key + "】已经存在，使用【" + value + "】覆盖【" + MainView.this.mapApkInfo.get(key) + "】");
                    } else {
                        MainView.this.logger.logInfo("添加属性成功");
                    }
                    MainView.this.mapApkInfo.put(key, value);
                    MainView.this._updateUI();
                }
            });
            attributeDialog.setVisible(true);
        });

        return center;
    }

    private JPanel initSouth() {
        JPanel south = new JPanel(new BorderLayout());

        JPanel top = new JPanel(new BorderLayout());
        top.setBorder(BorderFactory.createTitledBorder("保存信息"));
        south.add(top, BorderLayout.CENTER);

        JPanel left = new JPanel(new BorderLayout());
        top.add(left, BorderLayout.CENTER);

        this.tfExport = new JTextField();
//        this.tfExport.setEditable(false);
        left.add(this.tfExport, BorderLayout.CENTER);

        JButton btnExportBrowser = new JButton("浏览");
        left.add(btnExportBrowser, BorderLayout.EAST);
        btnExportBrowser.addActionListener(e -> {
            if ("".equals(this.apkImport)) {
                this.logger.logWarn("APK文件未指定");
                return;
            }
            // 选择apk文件
            JFileChooser fileChooser = new JFileChooser(new File("".equals(this.tfExport.getText()) ? this.apkImport : this.tfExport.getText()).getParent());
            fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
            int i = fileChooser.showSaveDialog(this);
            if (i == JFileChooser.APPROVE_OPTION) {
                File selFile = fileChooser.getSelectedFile();
                String outDirectory = selFile.getParent();

                String name = new File(this.apkImport).getName().replace(MainView.FILE_TYPE, "");
                this.apkExport = outDirectory + File.separator + name + MainView.SUFFIX_EXPORT + MainView.FILE_TYPE;
                this.tfExport.setText(this.apkExport);
            }
        });

        JButton btnSave = new JButton("保存");
        top.add(btnSave, BorderLayout.EAST);
        btnSave.addActionListener(e -> {
            try {
                if ("".equals(this.apkImport) || "".equals(this.apkExport)) {
                    this.logger.logWarn("输入/出路径有误");
                    return;
                }
                Files.copy(new File(this.apkImport).toPath(), new File(this.apkExport).toPath());
                ChannelWriter.put(new File(this.apkExport), this.mapApkInfo.get(MainView.KEY_CHANNEL), this.mapApkInfo);
                this.logger.logInfo("保存成功");
                File file = new File(this.apkExport);
                if (file.isDirectory())
                    Desktop.getDesktop().open(file);
                else
                    Desktop.getDesktop().open(file.getParentFile());
            } catch (Exception ex) {
                ex.printStackTrace();
                this.logger.logError("保存失败:" + ex.toString());
            }
        });

        this.logger = new Logger();
        this.logger.logWarn("测试");
        south.add(this.logger, BorderLayout.SOUTH);

        return south;
    }

    private JScrollPane initAttributes() {
        this.listAttribute = new JList();
        this.listAttribute.setListData(this.toAttributeStrings());
        this.listAttribute.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
        this.listAttribute.setVisibleRowCount(5);

        final JList<String> list = this.listAttribute;
        JPopupMenu popupMenu = new JPopupMenu();
        JMenuItem itemEdit = new JMenuItem("编辑");
        itemEdit.addActionListener(e -> {
            String str = this.listAttribute.getSelectedValue();
            String args[] = str.split(MainView.SEPARATOR);


            AttributeDialog attributeDialog = new AttributeDialog(MainView.this, "修改属性", args[0], args[1], new AttributeDialog.OnAttributeSaveClicked() {
                @Override
                void onClicked(String key, String value) {
                    super.onClicked(key, value);
                    MainView.this.mapApkInfo.put(key, value);
                    MainView.this._updateUI();
                }
            });
            attributeDialog.setKeyEditable(!args[0].equals(MainView.KEY_CHANNEL));
            attributeDialog.setVisible(true);
        });
        popupMenu.add(itemEdit);
        JMenuItem itemDelete = new JMenuItem("删除");
        itemDelete.addActionListener(e -> {
            if (this.listAttribute.getSelectedValue().startsWith(MainView.KEY_CHANNEL)) {
                this.logger.logError("渠道信息不能被删除");
                return;
            }
            int result = JOptionPane.showConfirmDialog(this, "确认删除 \"" + this.listAttribute.getSelectedValue() + "\" 吗？", "确认删除", JOptionPane.OK_CANCEL_OPTION);
            if (result == 0) {
                String str = this.listAttribute.getSelectedValue();
                String args[] = str.split(MainView.SEPARATOR);
                this.mapApkInfo.remove(args[0]);
                this._updateUI();
                int idx = this.listAttribute.getSelectedIndex();
                this.listAttribute.setSelectedIndex(Math.max(idx, 0));
                this.logger.logInfo("删除属性成功！" + this.listAttribute.getSelectedValue());
            } else {
                this.logger.logInfo("取消删除属性！" + this.listAttribute.getSelectedValue());
            }
        });
        popupMenu.add(itemDelete);
        this.listAttribute.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                super.mouseClicked(e);
                if (e.getButton() == 3 && list.getSelectedIndex() >= 0) {
                    popupMenu.show(list, e.getX(), e.getY());
                } else if (e.getClickCount() == 2) {
                    String str = list.getSelectedValue();
                    String args[] = str.split(MainView.SEPARATOR);

                    AttributeDialog attributeDialog = new AttributeDialog(MainView.this, "修改属性", args[0], args[1], new AttributeDialog.OnAttributeSaveClicked() {
                        @Override
                        void onClicked(String key, String value) {
                            super.onClicked(key, value);
                            MainView.this.mapApkInfo.put(key, value);
                            MainView.this._updateUI();
                        }
                    });
                    attributeDialog.setKeyEditable(!args[0].equals(MainView.KEY_CHANNEL));
                    attributeDialog.setVisible(true);
                }
            }
        });

        // 设置默认选中项
        this.listAttribute.setSelectedIndex(0);
        JScrollPane scrollPane = new JScrollPane(this.listAttribute);
        this.add(scrollPane, BorderLayout.CENTER);
        return scrollPane;
    }

    private void initDrop() {
        new DropTarget(this, DnDConstants.ACTION_COPY_OR_MOVE, new DropTargetAdapter() {
            @Override
            public void drop(DropTargetDropEvent dtde) {
                MainView.this.drop(dtde);
            }
        });
    }

    public void drop(DropTargetDropEvent dtde) {
        try {
            if (dtde.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
                // 接收拖拽来的数据
                dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
                java.util.List<File> list = (java.util.List<File>) dtde.getTransferable().getTransferData(DataFlavor.javaFileListFlavor);
                if (list.size() == 1) {
                    String apkPath = list.get(0).getAbsolutePath();
                    if (apkPath.endsWith(MainView.FILE_TYPE)) {
                        this.loadApk(apkPath);
                    } else {
                        this.logger.logWarn("不支持的文件类型！" + list.get(0).getPath());
                    }
                } else {
                    this.logger.logWarn("不支持多个文件!!!");
                }
                dtde.dropComplete(true);
            } else {
                this.logger.logWarn("不支持的文件类型!!!");
                dtde.rejectDrop();
            }
        } catch (Exception e) {
            e.printStackTrace();
            this.logger.logError("拖拽文件失败:" + e.toString());
        }
    }

    private void _updateUI() {
        this.lblChannel.setText(mapApkInfo.get(MainView.KEY_CHANNEL));
        this.listAttribute.setListData(this.toAttributeStrings());
        String name = new File(this.apkImport).getName().replace(MainView.FILE_TYPE, "");
        this.apkExport = this.apkImport.replace(name, name + MainView.SUFFIX_EXPORT);
        this.tfExport.setText(this.apkExport);
    }

    private void _updateRecent() {
        // 添加历史记录
        Object[] recents = UserDefault.getInstance().getValueForKey(KEY_RECENT, new Object[0]);
        this.recents = new ArrayList(Arrays.asList(recents));
        recentMenuItem.removeAll();
        for (int i = 0; i < this.recents.size(); i++) {
            JMenuItem item = new JMenuItem(this.recents.get(i));
            item.addActionListener(this);
            item.setName("recent_item_" + i);
            recentMenuItem.add(item);
        }
        recentMenuItem.addSeparator();

        JMenuItem clearItems = new JMenuItem("清空记录");
        clearItems.addActionListener(this);
        clearItems.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, ActionEvent.META_MASK));
        recentMenuItem.add(clearItems);
    }

    private Map<String, String> _getAPKInfo(String apkPath) {
        mapApkInfo = ChannelReader.getMap(new File(apkPath));
        if (mapApkInfo == null) {
            this.logger.logError("获取APK信息失败,请查看文件是否正确");
            return null;
        }
        return mapApkInfo;
    }

    private String[] toAttributeStrings() {
        String[] args = new String[this.mapApkInfo.size()];
        int i = 0;
        for (Map.Entry<String, String> entry : this.mapApkInfo.entrySet()) {
            args[i++] = (entry.getKey() + MainView.SEPARATOR + entry.getValue());
        }
        return args;
    }

    private boolean loadApk(String apkPath) {
        if (!new File(apkPath).exists()) {
            this.logger.logError("文件不存在!" + apkPath);
            this._updateRecent();
            return false;
        }
        // 放入到历史记录中
        this.recents.remove(apkPath);
        this.recents.add(0, apkPath);
        while (this.recents.size() > MAX_RECENT)
            this.recents.remove(this.recents.size() - 1);
        UserDefault.getInstance().setValueForKey(KEY_RECENT, JSONArray.parse(JSONArray.toJSONString(this.recents)));

        this.apkImport = apkPath;
        this.tfImport.setText(apkPath);
        this._getAPKInfo(apkPath);
        this._updateUI();
        this._updateRecent();
        this.logger.logInfo("APK加载成功");
        return true;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        JMenuItem menuItem = (JMenuItem) e.getSource();
        if (menuItem != null) {
            if (menuItem.getName() != null && menuItem.getName().startsWith("recent_item_")) {
                int idx = Integer.parseInt(menuItem.getName().substring(menuItem.getName().length() - 1));
                this.loadApk(this.recents.get(idx));
            } else if (menuItem.getAccelerator().equals(KeyStroke.getKeyStroke(KeyEvent.VK_S, ActionEvent.META_MASK | ActionEvent.SHIFT_MASK))) {
            } else if (menuItem.getAccelerator().equals(KeyStroke.getKeyStroke(KeyEvent.VK_C, ActionEvent.META_MASK))) {
                // 清空历史记录
                this.recents.clear();
                UserDefault.getInstance().setValueForKey(KEY_RECENT, JSONArray.parse(JSONArray.toJSONString(this.recents)));
                this._updateRecent();
            } else if (menuItem.getAccelerator().equals(KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.META_MASK))) {
                // 打开
                this._selectAPKFile();
            } else if (menuItem.getAccelerator().equals(KeyStroke.getKeyStroke(KeyEvent.VK_Q, ActionEvent.META_MASK))) {
                // 打开最近的文件
                System.exit(-1);
            } else if (menuItem.getAccelerator().equals(KeyStroke.getKeyStroke(KeyEvent.VK_L, ActionEvent.META_MASK))) {
                // 开源地址
                String url = "https://gitee.com/berwin/apkdistribution";
                try {
                    URI u = URI.create(url);
                    Desktop desktop = Desktop.getDesktop();
                    if (desktop.isSupported(Desktop.Action.BROWSE)) {
                        desktop.browse(u);
                    }
                } catch (MalformedURLException ex) {
                    ex.printStackTrace();
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            } else if (menuItem.getAccelerator().equals(KeyStroke.getKeyStroke(KeyEvent.VK_A, ActionEvent.META_MASK))) {
                // 关于
                String name = "关于软件";
                String version = "1.0.0";
                String content = "安卓渠道信息\r\n@版本: 1.0.0\r\n@作者: 唐博文";
                String txt = name + "(" + version + ")" + "\r\n\r\n" + content;
                JOptionPane.showMessageDialog(MainView.this, txt, "",
                        JOptionPane.INFORMATION_MESSAGE);
            }
        }

    }
}
